/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/common.hpp>
#include <baja/graphics/graphics.hpp>
#include <baja/math.hpp>

namespace baja { namespace app {

namespace g = baja::graphics;
namespace m = baja::math;

class origin_camera
{
private:
	origin_camera() : _angleX(0.f), _angleY(0.f), _angleZ(0.f), _distance(0.f)
	{
		// cache graphics
		_graphics = services::get<g::iengine>();
	}

public:
    friend class std::_Ref_count_obj<origin_camera>;
	static std::shared_ptr<origin_camera> create()
	{
		return std::make_shared<origin_camera>();
	}

	void getMatrix(m::matrix44* m) { *m = _matrix; }

	void set(
		const float32 angleX,
		const float32 angleY,
		const float32 angleZ,
		const float32 distance
		)
	{
		_angleX = angleX;
		_angleY = angleY;
		_angleZ = angleZ;
		_distance = distance;

		this->update();
	}

	void rotateDeltaXYZ(
		const float32 deltaX,
		const float32 deltaY,
		const float32 deltaZ
		)
	{
		_angleX += deltaX;
		_angleY += deltaY;
		_angleZ += deltaZ;
    
		this->update();
	}

	void move(const float32 delta)
	{
		_distance += delta;
		this->update();
	}

	float32 getDistance() { return _distance; }

private:

	void update()
	{
		m::matrix44 coordSystemMatrix;
		m::matrix44 newMatrix;

		newMatrix.setRotationXYZ(
			m::degToRad(_angleX),
			m::degToRad(_angleY),
			m::degToRad(_angleZ));

		coordSystemMatrix = _graphics.lock()->getCoordinateSystemMatrix();

		m::vector3d fwdVec;
		coordSystemMatrix.getForwardVector(&fwdVec);

		m::vector3d tmp;
        
		newMatrix.apply(fwdVec, &tmp);
		tmp.scale(-1.0f * _distance);

		m::point3d cameraPosition = m::point3d(tmp);
        
		newMatrix.setTranslation(cameraPosition);

		_matrix = newMatrix;

		_graphics.lock()->replaceCurrentCameraMatrix(_matrix);	
	}

private:

	m::matrix44 _matrix;

	float32 _angleX;
	float32 _angleY;
	float32 _angleZ;
	float32 _distance;

	std::weak_ptr<g::iengine> _graphics;
};

}}
